// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

package cn.org.dbtools.star.stack.driver;

import cn.org.dbtools.star.stack.util.ShellUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;

@Component
@Slf4j
public class ExecSqlShellClient {

    @Autowired
    public ExecSqlShellClient() {
    }

    public String getExecSqlCmd(Map<String, String> connectProperties) {
        String host = connectProperties.get("host");
        String port = connectProperties.get("port");
        String username = connectProperties.get("username");
        String password = connectProperties.get("password");
        String sql = connectProperties.get("sql");
        if (password == null || password.isEmpty()) {
            return String.format("mysql -h%s -P%s -u%s -e \"%s\"", host, port, username, sql);
        } else {
            return String.format("mysql -h%s -P%s -u%s -p%s -e \"%s\"", host, port, username, password, sql);
        }
    }

    private void execSql(Map<String, String> connectProperties, String sql) throws Exception {
        connectProperties.put("sql", sql);
        String cmd = getExecSqlCmd(connectProperties);
        log.info("exec sql. cmd:{}", cmd);
        int exitCode = ShellUtil.cmdExecute(cmd);
        if (exitCode != 0) {
            throw new Exception(String.format("exec sql fail. cmd:%s", cmd));
        }
    }

    public void updateUserPassword(String user, String newPassword, Map<String, String> connectProperties) throws Exception {
        try {
            String sql = "SET PASSWORD FOR '" + user
                    + "' = PASSWORD('" + newPassword + "')";
            execSql(connectProperties, sql);
            log.info("Update password successful");
        } catch (Exception e) {
            log.error("Update password error {}.", e);
            throw e;
        }
    }

    public void addFeFollower(List<String> feHostPorts, Map<String, String> connectProperties) throws Exception {
        try {
            for (String feObserverHostPort : feHostPorts) {
                String sql = "ALTER SYSTEM ADD FOLLOWER '" + feObserverHostPort + "'";
                execSql(connectProperties, sql);
                log.info("Add feFollower successful");
            }
        } catch (Exception e) {
            log.error("Add feFollower error {}.", e);
            throw e;
        }
    }

    public void addFeObserver(List<String> feObserverHostPorts, Map<String, String> connectProperties) throws Exception {
        try {
            for (String feObserverHostPort : feObserverHostPorts) {
                String sql = "ALTER SYSTEM ADD OBSERVER '" + feObserverHostPort + "'";
                execSql(connectProperties, sql);
                log.info("Add feObserver successful");
            }
        } catch (Exception e) {
            log.error("Add feObserver error {}.", e);
            throw e;
        }
    }

    public void addBe(List<String> beHostPorts, Map<String, String> connectProperties) throws Exception {
        try {
            for (String beHostPort : beHostPorts) {
                String sql = "ALTER SYSTEM ADD BACKEND '" + beHostPort + "'";
                execSql(connectProperties, sql);
                log.info("Add be error successful");
            }
        } catch (Exception e) {
            log.error("Add be error {}.", e);
            throw e;
        }
    }

    public void addBrokerName(List<String> brokerHostPorts, Map<String, String> connectProperties) throws Exception {
        try {
            if (brokerHostPorts != null && !brokerHostPorts.isEmpty()) {
                StringBuffer brokers = new StringBuffer();
                for (String brokerHostPort : brokerHostPorts) {
                    brokers.append("'");
                    brokers.append(brokerHostPort);
                    brokers.append("',");
                }
                // Remove the comma at the end
                brokers.deleteCharAt(brokers.length() - 1);
                String sql = "ALTER SYSTEM ADD BROKER broker_name " + brokers;

                execSql(connectProperties, sql);
                log.info("Add be successful");
            }
        } catch (Exception e) {
            log.error("Add be error {}.", e);
            throw e;
        }
    }
}
